package com.gzk.oeno.dao;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.SortedMap;
import java.util.TreeMap;

import org.hibernate.Session;
import org.hibernate.jdbc.Work;

import com.gzk.utils.CustomException;
import com.gzk.utils.db.AbstractSchemaManager;

public class DBSchema extends AbstractSchemaManager{

	
	private class ConnectionAdaptor implements Work{

		private final boolean isNew;
		private CustomException excep;
		
		public ConnectionAdaptor(boolean isNew){
			this.isNew = isNew;
		}
		
		@Override
		public void execute(Connection conn) throws SQLException {
			try {
				verifyDbSchema(conn, isNew);
			} catch (CustomException e) {
				excep = e;
			}
		}
		
		public CustomException getCustomException(){
			return excep;
		}
		
	}
	
	
	private static class DBVersionComparator implements Comparator<String>{

		@Override
		public int compare(String o1, String o2) {
			String[] v1 = o1.split(".");
			String[] v2 = o2.split(".");
			if (v1.length != 2 && v2.length != 2){
				return o1.compareTo(o2);
			}
			
			int vp1 = Integer.parseInt(v1[0]);
			int vp2 = Integer.parseInt(v1[0]);
			int compVP = Integer.valueOf(vp1).compareTo(Integer.valueOf(vp2));
			if (compVP != 0)
				return compVP;
			
			int vs1 = Integer.parseInt(v1[1]);
			int vs2 = Integer.parseInt(v1[1]);
			return Integer.valueOf(vs1).compareTo(Integer.valueOf(vs2));
		}
	}
	
	
	private static final DBSchema INSTANCE = new DBSchema();
	
	public static final DBSchema getInstance(){
		return INSTANCE;
	}
	
	private DBSchema(){};
	
	private static SortedMap<String, Collection<String>> statementsByVersion 
					= new TreeMap<String, Collection<String>>(new DBVersionComparator());
	
	@Override
	protected SortedMap<String, Collection<String>> getStatementsByVersion() {
		return statementsByVersion;
	}
	

	static {
		// Version 1.0
		Collection<String> statements = new ArrayList<String>();
		statements.add("CREATE_TABLE_DB_VERSION");
		statements.add("CREATE_TABLE_VINTYPE");
		statements.add("CREATE_IDX_VINTYPE");
		statements.add("CREATE_TABLE_PAYS");
		statements.add("CREATE_IDX_PAYS");
		statements.add("CREATE_TABLE_TERROIR");
		statements.add("CREATE_IDX_TERROIR");
		statements.add("CREATE_TABLE_APPELLATION");
		statements.add("CREATE_IDX_APPELLATION");
		statements.add("CREATE_TABLE_VIN");
		statements.add("CREATE_IDX_VIN");
		statements.add("CREATE_TABLE_RECOMPENSE");
		statements.add("CREATE_IDX_RECOMPENSE");
		statements.add("CREATE_TABLE_VINRECOMPENSE");
		statements.add("CREATE_IDX_VINRECOMPENSE");
		statements.add("CREATE_TABLE_CEPAGE");
		statements.add("CREATE_IDX_CEPAGE");
		statements.add("CREATE_TABLE_VINCOMPOSITION");
		statements.add("CREATE_IDX_VINCOMPOSITION");
		statements.add("CREATE_TABLE_VINCODIFTYPE");
		statements.add("CREATE_IDX_VINCODIFTYPE");
		statements.add("CREATE_TABLE_VINCODIF");
		statements.add("CREATE_IDX_VINCODIF");
		statements.add("CREATE_TABLE_VINLIEN");
		statements.add("CREATE_TABLE_VINPRIX");
		statements.add("CREATE_TABLE_UTILISATEUR");
		statements.add("CREATE_IDX_UTILISATEUR");
		statements.add("CREATE_TABLE_CAVE");
		statements.add("CREATE_IDX_CAVE");
		statements.add("CREATE_TABLE_BOUTEILLECAVE");
		statements.add("CREATE_TABLE_OPINION");
		statements.add("CREATE_IDX_OPINION");
		statements.add("CREATE_TABLE_CATEGORIECRITERE");
		statements.add("CREATE_IDX_CATEGORIECRITERE");
		statements.add("CREATE_TABLE_CATEGORIE");
		statements.add("CREATE_TABLE_CRITERE");
		statements.add("CREATE_TABLE_ECHELLECRITERE");
		statements.add("CREATE_IDX_ECHELLECRITERE");
		statements.add("CREATE_TABLE_OPINIONDETAIL");
		statements.add("CREATE_IDX_OPINIONDETAIL");
		statementsByVersion.put("1.0", statements);
	}
	
	
	public void verifyDbSchema(final boolean isNew) throws CustomException{
		ConnectionAdaptor adaptor = new ConnectionAdaptor(isNew);
		Session session = DBSave.get();
		try {
			session.doWork(adaptor);
			if (adaptor.getCustomException() != null)
				throw adaptor.getCustomException();
		} finally {
			session.close();
		}
	}
	
}
